﻿using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

namespace GameToolkit
{

    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]
    public class TaskResultAttribute : System.Attribute
    {
        public string PortName { get; set; }
        public Color PortColor { get; set; }
        public int Value { get; set; }
        public TaskResultAttribute(string portName, int value)
        {
            PortName = portName;
            PortColor = Color.white;
            Value = value;
        }

        public TaskResultAttribute(string portName, int value, string color)
        {
            PortName = portName;
            Color col;
            if (ColorUtility.TryParseHtmlString(color, out col))
                PortColor = col;
            else
                PortColor = Color.gray;
            Value = value;
        }

        public TaskResultAttribute()
        {
        }
    }

    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]
    public class HideTaskNodePortAttribute : System.Attribute
    {
        public bool HideGiveUpInput { get; set; }
        public bool HideAlways { get; set; }
        public bool HideFinish { get; set; }
        public bool HideGiveUp { get; set; }
    }

    public struct TaskResultDescripter
    {
        public int value;
        public string name;
        public Color color;
        public TaskResultDescripter(string name, int value, Color color)
        {
            this.value = value;
            this.name = name;
            this.color = color;
        }
    }

    public interface IDynamicTaskResult
    {
        int ResultCount { get; }
        TaskResultDescripter GetResultDescripter(int index);
    }

    /// <summary>
    /// 保留任务结果定义
    /// </summary>
    public enum EReservedTaskResult
    {
        Always = 0,
        GiveUp = -1, // 放弃执行
        Finish = -2, // 未放弃执行
    }

    public enum ETaskState
    {
        Inactive,
        Processing,
        Complete,
    }

    [System.Serializable]
    public abstract class TaskNode : TaskGraphAsset.NodeAsset
    {
        [System.Serializable]
        public struct Precondition : System.IEquatable<Precondition>
        {
            [SerializeReference, HideInInspector]
            public TaskNode node;

            // 0 for any result.
            [SerializeField]
            public int result;

            public bool IsTrue(TaskEntity entity)
            {
                var stat = entity == null ? ETaskState.Inactive : entity.State;
                if (result == (int)EReservedTaskResult.Always)
                    return stat != ETaskState.Processing;
                else if (result == (int)EReservedTaskResult.Finish)
                    return stat == ETaskState.Complete && entity.ResultValue != (int)EReservedTaskResult.GiveUp;
                else
                    return stat == ETaskState.Complete && entity.ResultValue == result;
            }

            public bool Equals(Precondition other)
            {
                return this.node == other.node && this.result == other.result;
            }
        }

        // 成功后执行的节点
        [SerializeField, HideInInspector]
#if UNITY_EDITOR
        internal
#endif
        Precondition[] m_Preconditions;


        [SerializeField, HideInInspector]
#if UNITY_EDITOR
        internal
#endif
        int m_ChildrenCount;
        internal int ChildrenBufferSize => m_ChildrenCount > 2 ? m_ChildrenCount : 2;

        [SerializeField, HideInInspector]
#if UNITY_EDITOR
        internal
#endif
        Precondition[] m_Killers;

        /// <summary>
        /// 是否创建时执行 wramup， 否则，warmup 将在节点或前置节点执行时执行 warmup
        /// </summary>
        public virtual bool WarmupOnCreate => false;
        /// <summary>
        /// 是否始终持久化数据， 否则只有在 Processing 状态持久化
        /// </summary>
        public virtual bool AlwaysPersistent => false;
        public int PreconditionCount => m_Preconditions == null ? 0 : m_Preconditions.Length;
        public Precondition GetPrecondition(int index)
        {
            return m_Preconditions[index];
        }

        public int KillerCount => m_Killers == null ? 0 : m_Killers.Length;
        public Precondition GetKiller(int index)
        {
            return m_Killers[index];
        }

        public abstract TaskEntity Create();
    }

    /// <summary>
    /// 任务对象
    /// 生命周期  OnWarmup -> OnEnter <-> OnExit -> OnRelease
    /// 注意： 该对象应该尽可能支持多线程异步操作
    /// </summary>
    public abstract class TaskEntity
    {
        System.Action<TaskEntity> mCallStateChanged;
        public event System.Action<TaskEntity> OnStateChanged
        {
            add
            {
                if (!mReleased)
                    mCallStateChanged += value;
            }
            remove
            {
                if (!mReleased)
                    mCallStateChanged -= value;
            }
        }

        TaskNode mNode;
        TaskGraph mCurrentGraph;
        public TaskNode Node => mNode;
        public string guid => mNode.guid;
        public TaskGraph activeGraph => mCurrentGraph;
        int mState;
        int mResult;
        bool mReleased;
        public ETaskState State => (ETaskState)mState;
        public int ResultValue => mResult;
        public virtual bool IsPersistent => true;

        public void SetState(ETaskState state, int result = (int)EReservedTaskResult.Finish)
        {
            if (mReleased)
                return;
            if(state == ETaskState.Inactive || state == ETaskState.Complete || state == ETaskState.Processing)
            {
                var stat = Interlocked.Exchange(ref mState, (int)state);
                var value = state == ETaskState.Complete ? Interlocked.Exchange(ref mResult, result) : result;
                if(stat != (int)state || value != result)
                {
                    if (mCurrentGraph != null)
                        mCurrentGraph.ReportTaskState(this);
                    OnValidateState((ETaskState)stat, value);
                    mCallStateChanged?.Invoke(this);
                }
            }
            else
            {
                Debug.LogError($"Invalid state: {(int)state}");
            }
        }

        public T GetNode<T>() where T : class
        {
            return mNode as T;
        }

        public void GiveUp()
        {
            if (State <= ETaskState.Processing)
                SetState(ETaskState.Complete, (int)EReservedTaskResult.GiveUp);
        }

        internal void InvokeCreate(TaskGraph graph, TaskNode node)
        {
            mNode = node;
        }

        internal void InvokeWarmup(TaskGraph graph)
        {
            mCurrentGraph = graph;
            OnWarmup(graph);
        }

        internal void InvokeOnEnter(TaskGraph graph)
        {
            OnEnter(graph);
        }

        internal void InvokeOnExit(TaskGraph graph)
        {
            OnExit(graph);
            GiveUp();
        }

        internal void InvokeRelease(TaskGraph graph)
        {
            mReleased = true;
            mCurrentGraph = null;
            mCallStateChanged = null;
            OnRelease(graph);
            mNode = null;
        }

        protected virtual void OnValidateState(ETaskState fromState, int fromResult) { }

        /// <summary>
        /// 预热剧情状态（该方法将在前置剧情状态变为 Processing 或者该剧情即将变为 Processing 状态时执行）
        /// </summary>
        protected virtual void OnWarmup(TaskGraph graph)
        {
        }

        /// <summary>
        /// 如果 graph 即将被销毁，则该方法将会被执行
        /// </summary>
        /// <param name="graph"></param>
        protected virtual void OnRelease(TaskGraph graph)
        {
        }

        protected abstract void OnEnter(TaskGraph graph);

        protected abstract void OnExit(TaskGraph graph);


    }

}
